import { useState } from "react";

interface State<D> {
  status: "idle" | "loading" | "success" | "error";
  error: Error | null;
  data: D | null;
}
const defaultState: State<null> = {
  status: "idle",
  error: null,
  data: null,
};
const defaultConfig = {
  throwOnError: false,
};
export const useAsync = <D>(
  initData?: State<D>,
  initConfig?: typeof defaultConfig
) => {
  const config = { ...defaultConfig, ...initConfig };
  const [state, setState] = useState<State<D>>({
    ...defaultState,
    ...initData,
  });
  //useState直接传入函数是惰性初始化，比如大组件首先让他加载一次，所以使用useState保存函数，不能直接传入函数
  const [retry, setRetry] = useState(() => () => {});

  const setData = (data: D) => {
    setState({
      data,
      status: "success",
      error: null,
    });
  };
  const setError = (error: Error) => {
    setState({
      error,
      status: "error",
      data: null,
    });
  };
  const run = (
    promise: Promise<D>,
    runConfig?: { retry: () => Promise<D> }
  ) => {
    if (!promise || !promise.then) {
      throw new Error("必须传入 Promise 类型的数据");
    }
    setRetry(() => () => {
      if (runConfig?.retry) {
        run(runConfig?.retry(), runConfig);
      }
    });
    setState({
      ...state,
      status: "loading",
    });
    return promise
      .then((res) => {
        setData(res);
        return res;
      })
      .catch((err) => {
        setError(err);
        console.log("config.throwOnError", config.throwOnError);
        if (config.throwOnError) return Promise.reject(err);
        return err;
      });
  };

  return {
    isIdle: state.status === "idle",
    isLoading: state.status === "loading",
    isSuccess: state.status === "success",
    isError: state.status === "error",
    setData,
    setError,
    run,
    // retry 被调用时重新跑一遍run，让state刷新一遍
    retry,
    ...state,
  };
};
